function varargout = BioPerf(varargin)
% BIOPERF Application M-file for BioPerf.fig
%    FIG = BIOPERF launch BioPerf GUI.
%    BIOPERF('callback_name', ...) invoke the named callback.

% Last Modified by GUIDE v2.0 16-Sep-2003 16:59:41
if nargin == 0  % LAUNCH GUI

    fig = openfig(mfilename,'reuse');

	% Generate a structure of handles to pass to callbacks, and store it. 
	handles = guihandles(fig);
	guidata(fig, handles);

    % allow multiple select on listbox
    handles.resultsListbox.max = 2;

    global FileResults;
    global ResultsList;

    clear FileResults;
    clear ResultsList;
    
    ResultsList = struct('');

    
	if nargout > 0
		varargout{1} = fig;
	end

elseif ischar(varargin{1}) % INVOKE NAMED SUBFUNCTION OR CALLBACK

	try
		if (nargout)
			[varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
		else
			feval(varargin{:}); % FEVAL switchyard
		end
	catch
		disp(lasterr);
	end

end


%| ABOUT CALLBACKS:
%| GUIDE automatically appends subfunction prototypes to this file, and 
%| sets objects' callback properties to call them through the FEVAL 
%| switchyard above. This comment describes that mechanism.
%|
%| Each callback subfunction declaration has the following form:
%| <SUBFUNCTION_NAME>(H, EVENTDATA, HANDLES, VARARGIN)
%|
%| The subfunction name is composed using the object's Tag and the 
%| callback type separated by '_', e.g. 'slider2_Callback',
%| 'figure1_CloseRequestFcn', 'axis1_ButtondownFcn'.
%|
%| H is the callback object's handle (obtained using GCBO).
%|
%| EVENTDATA is empty, but reserved for future use.
%|
%| HANDLES is a structure containing handles of components in GUI using
%| tags as fieldnames, e.g. handles.figure1, handles.slider2. This
%| structure is created at GUI startup using GUIHANDLES and stored in
%| the figure's application data using GUIDATA. A copy of the structure
%| is passed to each callback.  You can store additional information in
%| this structure at GUI startup, and you can change the structure
%| during callbacks.  Call guidata(h, handles) after changing your
%| copy to replace the stored original so that subsequent callbacks see
%| the updates. Type "help guihandles" and "help guidata" for more
%| information.
%|
%| VARARGIN contains any extra arguments you have passed to the
%| callback. Specify the extra arguments by editing the callback
%| property in the inspector. By default, GUIDE sets the property to:
%| <MFILENAME>('<SUBFUNCTION_NAME>', gcbo, [], guidata(gcbo))
%| Add any extra arguments after the last argument, before the final
%| closing parenthesis.



% --------------------------------------------------------------------
function varargout = plotROC_Callback(h, eventdata, handles, varargin)

global ResultsList;

Selected = get(handles.resultsListbox,'Value');
AllList = get(handles.resultsListbox,'String');

fig = figure;
hold on;
grid on;

for i = 1:length(Selected)
    plot(ResultsList(Selected(i)).procRes.FAR,(100 - ResultsList(Selected(i)).procRes.FRR),ResultsList(Selected(i)).plotStyle);
end

xlabel('False Accept Rate (%)');
ylabel('Probability of Rejection');
set(fig,'Name','Receiver Operating Curve');
legend(AllList(Selected),0);

L = line([0,100],[100,0]);
set(L,'color', [0.5 0.5 0.5])

grid off;
hold off;

% --------------------------------------------------------------------
function varargout = plotFARFRR_Callback(h, eventdata, handles, varargin)

global ResultsList;
Selected = get(handles.resultsListbox,'Value');
AllList = get(handles.resultsListbox,'String');

fig = figure;
hold on;
grid on;

for i = 1:length(Selected)
    plot(ResultsList(Selected(i)).procRes.Axis,ResultsList(Selected(i)).procRes.FAR,'b:',ResultsList(Selected(i)).procRes.Axis,ResultsList(Selected(i)).procRes.FRR,'r-');
end

xlabel('Threshold');
ylabel('Rate');
set(fig,'Name','False Accept and False Reject Rates');
legend('False Accept Rate','False Reject Rate');

grid off;
hold off;

% --------------------------------------------------------------------
function varargout = plotRank_Callback(h, eventdata, handles, varargin)

global ResultsList;

Selected = get(handles.resultsListbox,'Value');
if length(Selected) > 1
    msgbox('For this type of graph you can only have one set of results selected');
    return;
end

fig = figure;

hist(ResultsList(Selected).procRes.RankDist,length(ResultsList(Selected).procRes.RankDist));
H = hist(ResultsList(Selected).procRes.RankDist,length(ResultsList(Selected).procRes.RankDist));

xlabel('Rank position where probe was identified');
ylabel('Total');
set(fig,'Name',['Probe Rank Distribution for ' ResultsList(Selected).name]);
text = sprintf('Total Probes %d, %f%% ranked first', length(ResultsList(Selected).procRes.RankDist),H(1)/length(ResultsList(Selected).procRes.RankDist));
legend(text,0);

% --------------------------------------------------------------------
function varargout = errorTOff_Callback(h, eventdata, handles, varargin)

global ResultsList;

Selected = get(handles.resultsListbox,'Value');
AllList = get(handles.resultsListbox,'String');

fig = figure;
hold on;
grid on;

for i = 1:length(Selected)
    plot(ResultsList(Selected(i)).procRes.FAR,ResultsList(Selected(i)).procRes.FRR,ResultsList(Selected(i)).plotStyle);
end

xlabel('False Accept Rate (%)');
ylabel('False Reject Rate (%)');
set(fig,'Name','Error Trade Off Curve');
legend(AllList(Selected),0);

L = line([0,100],[0,100]);
set(L,'color', [0.5 0.5 0.5]);

grid off;
hold off;

% --------------------------------------------------------------------
function varargout = ccmatrix_Callback(h, eventdata, handles, varargin)

global ResultsList;

Selected = get(handles.resultsListbox,'Value');
if length(Selected) > 1
    msgbox('For this type of graph you can only have one set of results selected');
    return;
end

fig = figure;

imagesc(ResultsList(Selected).procRes.ccmatrix);

if ResultsList(Selected).probesInColumns == 1
    xlabel('Probes');
    ylabel('Gallery');
else
    ylabel('Probes');
    xlabel('Gallery');
end
set(fig,'Name',['Cross Coorlation Matrix ' ResultsList(Selected).name]);

% --------------------------------------------------------------------
function varargout = ScoreDist_Callback(h, eventdata, handles, varargin)

global ResultsList;

Selected = get(handles.resultsListbox,'Value');
if length(Selected) > 1
    msgbox('For this type of graph you can only have one set of results selected');
    return;
end

fig = figure;

hold on;

len = length(ResultsList(Selected).rawRes.sheep);

[S,Sc] = hist(ResultsList(Selected).rawRes.sheep,len/10);
[W,Wc] = hist(ResultsList(Selected).rawRes.wolves,len/10);

bar(Wc,W/(max(W)),0.5,'b');
bar(Sc,S/(max(S)),0.5,'r');

xlabel('Score');
ylabel('Total (Normalised)');
set(fig,'Name','Sheep and Wolf Score Distribution');
legend('Wolves','Sheep');

hold off;


% --------------------------------------------------------------------
function varargout = resultsListbox_Callback(h, eventdata, handles, varargin)


% --------------------------------------------------------------------
function varargout = OpenResultFile_Callback(h, eventdata, handles, varargin)

global FileResults;

[resFilename, resFilepath] = uigetfile({'*.bpr', 'BioPerf Result Files (*.bpr)';'*.mat', 'Cross Coorelation Matrix Files (*.mat)';'*.*', 'Engine Output file (*.*) - Must be processed'}, 'Open Result File');
if isequal(resFilename,0)|isequal(resFilepath,0)
   return;
end

clear procRes;
clear rawRes;

% Load files and Do result Validity check
FileResults = struct('name','untitled','filename',resFilename,'filepath',resFilepath,'type',0,'plotStyle','b-','info','','procRes',[],'rawRes',[],'probesInColumns',0);
FileResults.filename = resFilename;
FileResults.filepath = resFilepath;

if cmpiExt(resFilename,'mat') % cross coorelation matrix only file
    M = load([resFilepath resFilename]);
    a = fieldnames(M);
    siz = size(a);
    if siz(1) > 1
        msgbox('More Than one set of results in file, Where only one Crosscorrelation matrix expected');
        return
    end
    procRes = struct('ccmatrix',getfield(M,a{:}));
    siz = size(procRes.ccmatrix);
    if siz(1,2) ~= siz(1,1)
        disp('Cross correlation matrix not square')
    elseif siz < 2
        disp('No Cross correlation matrix not found')
    end
    FileResults.procRes = procRes;
    FileResults.name = [strtok(resFilename,'.')];
    FileResults.type = 1;
elseif cmpiExt(resFilename,'bpr') % Processed Results File
    temp = sprintf('load ''%s'' -MAT',[resFilepath resFilename]);
    eval(temp);
    FileResults.type = 2;
else % Raw Engine output file
    FileResults.name = [strtok(resFilename,'.')];
    FileResults.type = 0;
    set(handles.parserInput,'Enable','on');
end

updateFiledetails(handles);
    
% --------------------------------------------------------------------
function varargout = addResults_Callback(h, eventdata, handles, varargin)

global FileResults;
global ResultsList;

if processFileResults(handles) == 1
    return;
end


% Add to global full results lists
if exist('ResultsList') == 0 % does not exist
    ResultsList = FileResults;
elseif isempty('ResultsList') == 1
    ResultsList = FileResults;
else
    if length(ResultsList) == 0
        ResultsList = FileResults;
    else
        ResultsList(length(ResultsList) + 1) = FileResults;
    end
end
    
UpdateResultsList(handles);
updateFiledetails(handles);

% --------------------------------------------------------------------
function updateFiledetails(handles)

global  FileResults;

set(handles.resName ,'String', FileResults.name );
set(handles.resultFile ,'String', [FileResults.filepath FileResults.filename]);
col = get(handles.colour,'String');
for i = 1:length(col)
    if strcmp(FileResults.plotStyle(1,1),strtok(char(col(i)))) == 1
        set(handles.colour,'Value',i)
        break;
    end
end
type = get(handles.style,'String');

if length(FileResults.plotStyle) == 3
    filestyle = FileResults.plotStyle(1,2:3);
else
    filestyle = FileResults.plotStyle(1,2);
end
    
for i = 1:length(type)
    if strcmp(filestyle,strtok(char(type(i)))) == 1
        set(handles.style,'Value',i)
        break;
    end
end

if FileResults.type == 0
    set(handles.parserInput ,'Enable', 'on' );
else
    set(handles.parserInput ,'Enable', 'off' );
    siz = size(FileResults.procRes.ccmatrix);
    set(handles.info,'String', sprintf('%d x %d Square Matrix found. %s',siz(1,1),siz(1,2),FileResults.info));
end

if FileResults.probesInColumns == 1
    set(handles.probesInColumns,'Value',1 )
else
    set(handles.probesInColumns,'Value',0 )
end

% --------------------------------------------------------------------
function UpdateResultsList(handles)

global ResultsList;

if exist('ResultsList')
    for i = 1: length(ResultsList)
        list{i} = ResultsList(i).name;
    end
else
    list = {};
end
    
set(handles.resultsListbox,'String',list);
set(handles.resultsListbox,'Value',1);


% --------------------------------------------------------------------

function rtn = cmpiExt(filename,ext)

rtn = 0;
len = length(filename);
if filename(len - 3) ~= '.'
   disp('filename extension error');
   return;
end
    
for i = 1:3
    if filename(len - 3 + i) ~= ext(i)
        disp('filename extension error');
        return;
    end
end

rtn = 1;

% --------------------------------------------------------------------
function varargout = saveRes_Callback(h, eventdata, handles, varargin)

global  FileResults;

name = [FileResults.name '.bpr'];
[filename, pathname] = uiputfile(name, 'Save File');
if isequal(filename,0)|isequal(pathname,0)
    disp('File not found')
    return;
end

if processFileResults(handles) == 1
    return;
end

FileResults.type = 2;

FileResults.filename = filename;
FileResults.filepath = pathname;

name = sprintf('save ''%s'' FileResults -MAT',[pathname filename]);
eval(name);

% --------------------------------------------------------------------
function varargout = style_Callback(h, eventdata, handles, varargin)




% --------------------------------------------------------------------
function varargout = clearList_Callback(h, eventdata, handles, varargin)

global ResultsList;

ResultsList = struct('');

set(handles.resultsListbox,'String',{});


% --------------------------------------------------------------------
function varargout = parserInput_Callback(h, eventdata, handles, varargin)

% --------------------------------------------------------------------
function rtn = processFileResults(handles)

global FileResults;

name = get(handles.resName,'String');
if isempty(name)
    msgbox('No Results Set Name');
    return;
end

Changed = FileResults.probesInColumns;
FileResults.probesInColumns = get(handles.probesInColumns,'Value');

FileResults.name = name;
a = get(handles.colour,'String');
b = char(a(get(handles.colour,'Value')));
c = get(handles.style,'String');
d = char(c(get(handles.style,'Value')));
FileResults.plotStyle = strcat(b(1),strtok(d));

h = waitbar(0,'Processing Results ...','CreateCancelBtn','close');

rtn = 0;
if FileResults.type == 0 % raw datatype - parse the data
    parser = get(handles.parserInput,'String');
    if isempty(parser) == 1
        msgbox('No Parser Defined');
        rtn = 1;
        return;
    end
    
    waitbar(0.2,h);
    % Parse the input file into matrix with [probe,gallery,score]
    rawRes = feval(parser,FileResults.filename);
    
    % if results in range -inf to zero normalise and send message
    [rawRes,info] = CheckResults(handles,rawRes);
    FileResults.info = [FileResults.info info];
    
    waitbar(0.6,h);
    % Make Cross Correlation Matrix from Raw results
    FileResults.procRes.ccmatrix = rawResToCCmatrix(rawRes);
    
    waitbar(0.7,h);
    % Create Sheep and wolf arrays from raw results
    [FileResults.rawRes.sheep,FileResults.rawRes.wolves] = GenSheepWolves(rawRes);
    
    waitbar(0.8,h);
    % Create Rank Distrubition of probe images
    FileResults.procRes.RankDist = GenRankDist(FileResults.procRes.ccmatrix,FileResults.probesInColumns);
    
    waitbar(0.9,h);
    % Calculate FAR and FRR at all threshold points
    [FileResults.procRes.FAR,FileResults.procRes.FRR,FileResults.procRes.Axis] = GenFARFRR(FileResults.rawRes.sheep,FileResults.rawRes.wolves,100); % last param is number of points to calculate scores at
    
elseif FileResults.type == 1 % Cross Coorelation matrix - process the matrix
    
    waitbar(0.2,h);
    % if results in range -inf to zero normalise and send message
    [FileResults.procRes.ccmatrix,info] = CheckResults(handles,FileResults.procRes.ccmatrix);
    FileResults.info = [FileResults.info info];

    waitbar(0.4,h);
    % Create Rank Distrubition of probe images
    FileResults.procRes.RankDist = GenRankDist(FileResults.procRes.ccmatrix,FileResults.probesInColumns);
    
    waitbar(0.6,h);
    % Create Sheep and wolf arrays from ccmatrix
    [FileResults.rawRes.sheep,FileResults.rawRes.wolves] = GenSheepWolves(FileResults.procRes.ccmatrix);

    waitbar(0.8,h);
    % Calculate FAR and FRR at all threshold points
    [FileResults.procRes.FAR,FileResults.procRes.FRR,FileResults.procRes.Axis] = GenFARFRR(FileResults.rawRes.sheep,FileResults.rawRes.wolves,100); % last param is number of points to calculate scores at
    
elseif FileResults.type == 2 & FileResults.probesInColumns == Changed% Processed Results that have changed

    % Create Rank Distrubition of probe images
    FileResults.procRes.RankDist = GenRankDist(FileResults.procRes.ccmatrix,FileResults.probesInColumns);
    
end

if exist('h')
    delete(h);
end

% --------------------------------------------------------------------
function varargout = resName_Callback(h, eventdata, handles, varargin)






% --------------------------------------------------------------------
function varargout = probesInColumns_Callback(h, eventdata, handles, varargin)

